package com.tmt.im.service.interfaces.impl;

import com.alibaba.fastjson2.JSONObject;
import com.tmt.im.common.Constant;
import com.tmt.im.common.enums.ChatSessionType;
import com.tmt.im.common.vo.NewChatSessionVo;
import com.tmt.im.common.vo.QueryMembersRequest;
import com.tmt.im.common.yunxin.ErrorCode;
import com.tmt.im.common.yunxin.YunXinHelper;
import com.tmt.im.service.config.beans.YunXinProperties;
import com.tmt.im.service.controller.vo.*;
import com.tmt.im.service.helper.UpdateSessionVoHelper;
import com.tmt.im.service.interfaces.IYunXinInterface;
import org.apache.ignite.Ignite;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Author wuyi
 * @Date 2024/9/16 9:23
 * @Version 1.0
 **/
@Order(0)
public class YunXinInterfaceImpl_V9 implements IYunXinInterface, ApplicationContextAware {

    private static final String CREATE_SESSION_URL = "https://api.netease.im/nimserver/team/create.action";

    private static final String SESSION_DETAIL_URL= "https://api.netease.im/nimserver/team/queryDetail.action";

    private static final String GET_ALL_IN_SESSION_URL = "https://api.netease.im/nimserver/team/joinTeams.action";

    private static final String DELETE_SESSION_URL = "https://api.netease.im/nimserver/team/remove.action";

    private static final String TRANSFER_SESSION_URL = "https://api.netease.im/nimserver/team/changeOwner.action";

    private static final String ADD_MANAGER_URL = "https://api.netease.im/nimserver/team/addManager.action";

    private static final String REMOVE_MANAGER_URL = "https://api.netease.im/nimserver/team/removeManager.action";

    private static final String UPDATE_SESSION_URL = "https://api.netease.im/nimserver/team/update.action";

    private static final String INVITE_MEMBER_URL = "https://api.netease.im/nimserver/team/add.action";

    private static final String KICK_OUT_MEMBER_URL = "https://api.netease.im/nimserver/team/kick.action";

    private static final String LEAVE_SESSION_URL = "https://api.netease.im/nimserver/team/leave.action";

    private static final String BANNED_SESSION_URL = "https://api.netease.im/nimserver/team/muteTlistAll.action";

    private static final String BANNED_MEMBER_URL = "https://api.netease.im/nimserver/team/muteTlist.action";

    private static final String NO_DISTURBING_URL = "https://api.netease.im/nimserver/team/muteTeam.action";

    private static final String UPDATE_MEMBER_NICK_URL = "https://api.netease.im/nimserver/team/updateTeamNick.action";


    private YunXinProperties yunXinProperties;

    private Ignite ignite;

    @Override
    public JSONObject createSession(Long creatorId, String creatorNick, NewChatSessionVo sessionVo, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();

            /*************必须要设置的属性*****************/

            reqParam.add("tname", sessionVo.getName());
            reqParam.add("owner", "" + creatorId);
            reqParam.add("members", sessionVo.getInvitedIds().stream().map(x -> "" + x).collect(Collectors.toList()));
            reqParam.add("msg", sessionVo.getInviteMsg());
            /**
             * 群创建完成后，通过 SDK 侧操作申请入群的验证方式
             * 0，不用验证。1，需要群主或管理员的验证。2，不允许任何人加入
             */
            reqParam.add("joinmode", 1);

            /**
             * 邀请权限，即谁可以邀请他人入群
             * 0，群主和管理员（默认）；1，所有人
             */
            reqParam.add("invitemode", 1);

            /*************可选设置的属性*****************/

            /**
             * 创建群时，若 members 不为空，那么邀请其入群是否需要同意
             * 0，不需要被邀请人同意加入群（默认）。1，需要被邀请人同意才可以加入群
             * 只有当 beinvitemode = 0 时，magree 才能设为 1，即 时，magree =1 才生效。
             */
            reqParam.add("magree", 0);

            /**
             * 群创建完成后，邀请入群时是否需要被邀请人的同意
             * 0，需要同意（默认）。1，不需要同意
             */
            reqParam.add("beinvitemode", 1);

            if (StringUtils.hasText(sessionVo.getAnnouncement())) {
                reqParam.add("announcement", sessionVo.getAnnouncement());
            }
            if (StringUtils.hasText(sessionVo.getIntro())) {
                reqParam.add("intro", sessionVo.getIntro());
            }

            JSONObject jsonObject = YunXinHelper.exchange(CREATE_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                //读取群组详情，获取最大用户数量。
                Long tid = jsonObject.getLong("tid");
                JSONObject tmpJson = getSessionDetail(tid, error);
                if (tmpJson != null){
                    return tmpJson;
                }
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject getSessionDetail(Long tid, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);

            JSONObject jsonObject = YunXinHelper.exchange(SESSION_DETAIL_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject getAllInSession(Long creatorId, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("accid", "" + creatorId);

            JSONObject jsonObject = YunXinHelper.exchange(GET_ALL_IN_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject updateSession(Long sessionOwnerId, ChatSessionType type, UpdateSessionRequest request, StringBuilder error) {
        if (request.getChatBannedMode() != null){
            //如果修改了群禁言状态，则要同步云信平台。
            int muteType = Boolean.TRUE.equals(request.getChatBannedMode()) ? 0 : 3;
            if (!bannedSession(sessionOwnerId, type, request.getTid(), muteType, error)){
                return null;
            }
        }
        try {
            //将请求对象转换为Map对象。
            MultiValueMap<String, Object> map = UpdateSessionVoHelper.convertTo(sessionOwnerId, type, request);
            if (map.size() >= 3) {
                JSONObject jsonObject = YunXinHelper.exchange(UPDATE_SESSION_URL, HttpMethod.POST, map, yunXinProperties);
                Long code = jsonObject.getLong("code");
                if (code == 200L) {
                    return jsonObject;
                }
                throwExceptionByCode(code, jsonObject);
            }
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public boolean deleteSession(Long operatorId, ChatSessionType type, Long tid, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + operatorId);

            JSONObject jsonObject = YunXinHelper.exchange(DELETE_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean bannedSession(Long operatorId, ChatSessionType type, Long tid, int muteType, StringBuilder error){
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + operatorId);
            reqParam.add("muteType", muteType);

            JSONObject jsonObject = YunXinHelper.exchange(BANNED_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }


    @Override
    public boolean updateSessionJoinMode(Long tid, Long ownerId, int joinMode, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + ownerId);
            /**
             * 群创建完成后，通过 SDK 侧操作申请入群的验证方式
             * 0，不用验证；1，需要群主或管理员的验证；
             */
            reqParam.add("joinmode", joinMode);
            /**
             * 邀请权限，即谁可以邀请他人入群
             * 0，群主和管理员（默认）；1，所有人
             */
            reqParam.add("invitemode", 1);

            JSONObject jsonObject = YunXinHelper.exchange(UPDATE_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean transferSession(Long operatorId, Long tid, ChatSessionType type, Long newOwnerId, boolean leave, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + operatorId);
            reqParam.add("newowner", "" + newOwnerId);
            reqParam.add("leave", leave ? 1 : 2);

            JSONObject jsonObject = YunXinHelper.exchange(TRANSFER_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean addManager(Long operatorId, Long tid, ChatSessionType type, List<Long> managers, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + operatorId);
            reqParam.add("members", managers.stream().map(x -> "" + x).toList());

            JSONObject jsonObject = YunXinHelper.exchange(ADD_MANAGER_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean removeManager(Long operatorId, Long tid, ChatSessionType type, List<Long> managers, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + operatorId);
            reqParam.add("members", managers.stream().map(x -> "" + x).toList());

            JSONObject jsonObject = YunXinHelper.exchange(REMOVE_MANAGER_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public JSONObject queryMembers(Long operatorId, Long tid, ChatSessionType type, QueryMembersRequest request, StringBuilder error) {
        return null;
    }

    @Override
    public JSONObject joinSession(Long operatorId, Long tid, ChatSessionType type, int beInvitedMode,
                                  String inviteMsg, List<Long> memberIds, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + operatorId);
            reqParam.add("members", memberIds.stream().map(x -> "" + x).toList());
            //不需要被邀请人同意
            reqParam.add("magree", 0);

            if (!StringUtils.hasText(inviteMsg)){
                inviteMsg = yunXinProperties.getGroupInitParam().getInviteMsg();
            }
            reqParam.add("msg", inviteMsg);

            JSONObject jsonObject = YunXinHelper.exchange(INVITE_MEMBER_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject kickOutSession(Long operatorId, Long tid, ChatSessionType type, List<Long> memberIds, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + operatorId);
            if (memberIds.size() == 1) {
                reqParam.add("member", "" + memberIds.get(0));
            } else {
                reqParam.add("members", memberIds.stream().map(x -> "" + x).toList());
            }
            JSONObject jsonObject = YunXinHelper.exchange(KICK_OUT_MEMBER_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L || (code == 414 && jsonObject.getString("desc").contains("not team member"))) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public boolean leaveSession(Long operatorId, Long tid, ChatSessionType type, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("accid", "" + operatorId);

            JSONObject jsonObject = YunXinHelper.exchange(LEAVE_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean updateMemberNick(Long currentUserId, Long tid, ChatSessionType type, UpdateMemberNickRequest request, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + currentUserId);
            reqParam.add("accid", "" + request.getMemberId());
            reqParam.add("nick", request.getNick());

            JSONObject jsonObject = YunXinHelper.exchange(UPDATE_MEMBER_NICK_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public JSONObject bannedMembers(Long currentUserId, Long tid, ChatSessionType type, ChatBannedRequest request, StringBuilder error) {
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("owner", "" + currentUserId);
            reqParam.add("mute", request.getChatBanned() ? 1 : 0);

            //为了后续处理方便，模拟V9版本批量处理返回的结果信息的结构。
            List<String> ids = new ArrayList<>();
            JSONObject faccid = new JSONObject();
            faccid.put("accid", ids);
            faccid.put("msg", "云信接口禁言失败");

            JSONObject result = new JSONObject();
            result.put("code", 200);
            result.put("faccid", faccid);

            for (Long memberId : request.getMemberIds()) {
                reqParam.remove("accid");
                reqParam.add("accid", "" + memberId);
                JSONObject jsonObject = YunXinHelper.exchange(BANNED_MEMBER_URL, HttpMethod.POST, reqParam, yunXinProperties);
                Long code = jsonObject.getLong("code");
                if (code != 200L) {
                    ids.add("" + memberId);
                    //构造返回信息。
                    faccid.put("msg", faccid.get("msg") + "|" + code + "=" + jsonObject.getString("desc"));
                }
            }
            return result;

        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    public boolean noDisturbingMember(Long currentUserId, Long tid, ChatSessionType type, NoDisturbingRequest request, StringBuilder error){
        try {
            MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
            reqParam.add("tid", tid);
            reqParam.add("accid", "" + currentUserId);
            reqParam.add("ope", request.getNoDisturbing() ? 1 : 2);

            JSONObject jsonObject = YunXinHelper.exchange(NO_DISTURBING_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean sendCustomizedMessage(Long senderId, int type, Long receiverId, String content, String sound, Map<String, Object> notification_config, Map<String, Object> push_config, StringBuilder error) {
        return false;
    }

    @Override
    public boolean sendCustomizedMessages(Long senderId, List<Long> receiverIds, String content, String sound, Map<String, Object> notification_config, Map<String, Object> push_config, StringBuilder error) {
        return false;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        yunXinProperties = applicationContext.getBean(YunXinProperties.class);
        ignite = applicationContext.getBean(Ignite.class);
    }

    private void throwExceptionByCode(Long code, JSONObject jsonObject) throws Exception {
        String errorInfo = ErrorCode.getErrorMessage(Constant.YUN_XIN_API_VERSION, code);
        if (StringUtils.hasText(errorInfo)) {
            if (code == 414L) {
                errorInfo = MessageFormat.format(errorInfo, jsonObject.get("desc"));
            }
            throw new Exception(errorInfo);
        } else {
            throw new Exception(MessageFormat.format("云信业务错误:{0}", "" + code));
        }
    }
}
